if(!Util.isValid(QSAPI,true,true)){
      var QSAPI={Widget:{}};
}else if(!QSAPI.Widget){
      QSAPI.Widget={};
}
if(!Util.isValid(GB_AC_FIELD,true,true,true)){
    var GB_AC_FIELD={
        "SecId": "SecId",
        "Name": "OS01W",
        "CUSIP":"OS05K",
        "ISIN": "OS05J",
        "Ticker": "OS001",
        "SecurityType": "OS010",
        "MICCode": "LS01Z",
        "PerformanceId": "OS06Y",
        "CountryName": "XI018",
        
        "TFTicker":"AC001",
        "TFName":"AC020",
        "TFForexTicker":"AC009",
        "TFForexName":"AC010",
        "TFForexMIC":"AC011",
        "TFForexExchangeID":"AC030",
        "TFSecurityType":"AC003",
        "TFExchangeID":"AC018",
        "TFCurrencyMarket":"AC019",
        "UserTicker":"ClientTicker"
    };
}
if(!Util.isValid(GB_SECURITY_NAME,true,true,true)){
    var GB_SECURITY_NAME={
        "ST": "Equities",
        "Funds": "Funds",
        "Futures": "Futures",
        "FOREX": "Forex",
        "Bonds": "Bonds",
        "XI": "Index",
        "FE": "ETF",
        "FC": "Closed-End Fund",
        "FO": "Mutual Fund",
        1:"Equities",
        2:"Option",
        3:"Futures",
        7:"Corporate Bonds",
        8:"Mutual Fund",
        9:"Government Bonds",
        10:"Index",
        13:"Strategies & Spreads",
        16:"Unspecified Bonds"
    };
}

if(!Util.isValid(GB_AC_SECURITY,true,true,true)){
    var GB_AC_SECURITY={
        "EQUITIES":"Equities",
        "FUNDS":"Funds",
        "FUTURES":"Futures",
        "INDEX":"Index",
        "FOREX":"Forex",
        "BONDS":"Bonds",
        "ETF":"ETF",
        "CEF":"CEF",
        "MUTUALFUND":"MutualFund",
        "OPTION":"Option",
        "OTHERS":"Others"
    };
}

QSAPI.Widget.AutoCompleteFilter=function(instid){
    this.instid=instid;
    this.replaceC="-C";
    this.replaceU="-U";
    this.exchange={
        "XNYS":this.replaceU,
        "XNAS":this.replaceU,
        //"XASE":this.replaceU,
        "3":this.replaceU,//cboe
        //"USA":this.replaceU,
        
        "XTSX":this.replaceC,
        "XTSE":this.replaceC,
        "127":this.replaceC,
        "128":this.replaceC//128:2
        //"CAN":this.replaceC,
        //"52":this.replaceC//Morningstar Funds,MF
    };
};
QSAPI.Widget.AutoCompleteFilter.prototype={
        setValue:function(val){//when search from db
            var reg =/(\-(\U|\C))|(\-)$/ig;
            return val.replace(reg,"");
        },
        createRowUI:function(category,rowData){
            return "<td class='qs-autocomplete-col-clientticker'>"+ rowData[GB_AC_FIELD["UserTicker"]]+ "</td>"+
            "<td class='qs-autocomplete-col-name'>" + rowData[GB_AC_FIELD["Name"]]+"</td>";
        },
        getColumnsCount:function(){
            return 2;
        },
        genClientData:function(input,ticker){//when data arrived
            var rgx = new RegExp(input, "i");           
            //ticker["clientTicker"] = ticker[GB_AC_FIELD["Ticker"]]+this._getSuffix(ticker);
            if(typeof ticker[GB_AC_FIELD["UserTicker"]]=='undefined'){
                ticker[GB_AC_FIELD["UserTicker"]] = ticker.origin;
            }
            var clientTicker = ticker[GB_AC_FIELD["UserTicker"]];
            ticker["orginClientTicker"] = clientTicker;
            var tmatch = clientTicker.match(rgx);
            if(tmatch!=null){
                ticker[GB_AC_FIELD["UserTicker"]] = clientTicker.replace(rgx, "<b class='highlight'>" + tmatch[0] + "</b>");
            }
        },
        _getSuffix:function(ticker){
            /*
            var replaceStr = this.exchange[ticker[GB_AC_FIELD["MICCode"]]];//exchange
            if(!replaceStr){
                replaceStr = this.exchange[ticker[GB_AC_FIELD["TFExchangeID"]]];//MICCode
            }
            if(!replaceStr){
                replaceStr = this.exchange[ticker[GB_AC_FIELD["CountryName"]]];//MICCode
            }
            return (replaceStr||"");
            */
        }
};
QSAPI.Widget.AutoCompleteDataManager = (function(){
    var dataUrls ="acb.jsp";
    var config={
        path:'./',
        instid:'QSDEMO'
    };
    var idMap={};
    var isInit=false;
    var cacheData = {};
    var cacheCallback = {};
    var _checkDataPermission = function(micCode,exchId,securityType,currencyMarket){
        var isValid=true;
        if(QSAPI.DataManager){
            isValid = QSAPI.DataManager._checkAutoCompletePermission(micCode,exchId,securityType);
        }
        return isValid;
    };
    var _setCategory=function(ticker){
        //mutual fund
        if(ticker[GB_AC_FIELD["SecurityType"]]=="ST"&&ticker[GB_AC_FIELD["TFSecurityType"]]=="8"){
            ticker[GB_AC_FIELD["SecurityType"]]="FO";
        }
    };
    var _dataOnArrived=function(data){
        var o=null;
        if(typeof(data)!="string"){
            o=data;
        }else{
            o = eval("(" + data.replace("\r\n","") + ")");
        }
        var arrkey = "";
        var requestID = o.id, result = o.result, item = null,iData = {};
        var tempPidMap = {},ticker=null,tfsecurityType=null,securityType=null,pid=null;
        for (var i = 0; i < result.length; i++) {
            item = result[i];
            if(!item){
                continue;
            }
            securityType = item[GB_AC_FIELD["SecurityType"]].toUpperCase();
            tfsecurityType= item[GB_AC_FIELD["TFSecurityType"]];
            if(securityType=="FOREX"){
                item[GB_AC_FIELD["Ticker"]]=item[GB_AC_FIELD["TFForexTicker"]].replace("FLIT","");
                item[GB_AC_FIELD["Name"]]=item[GB_AC_FIELD["TFForexName"]];
                item[GB_AC_FIELD["MICCode"]]=item[GB_AC_FIELD["TFForexMIC"]];//
            }else{
                item[GB_AC_FIELD["MICCode"]]=item[GB_AC_FIELD["MICCode"]].substr(6).replace(/\$/ig,"");
            }
            if(tfsecurityType==10){//forex
                if(item[GB_AC_FIELD["TFExchangeID"]]==200&&item[GB_AC_FIELD["TFForexExchangeID"]]==213){
                    item[GB_AC_FIELD["TFExchangeID"]] =213;
                }   
            }
            if(!_checkDataPermission(item[GB_AC_FIELD["MICCode"]],item[GB_AC_FIELD["TFExchangeID"]],tfsecurityType,item[GB_AC_FIELD["TFCurrencyMarket"]])){ 
                continue; 
            }
            
            ticker = item[GB_AC_FIELD["Ticker"]];
            if(ticker==""&&item[GB_AC_FIELD["TFTicker"]]&&item[GB_AC_FIELD["TFTicker"]]!=""){
                item[GB_AC_FIELD["Ticker"]] = item[GB_AC_FIELD["TFTicker"]];
                ticker = item[GB_AC_FIELD["TFTicker"]];
            }
            if(securityType ==""){
                item[GB_AC_FIELD["SecurityType"]] = tfsecurityType;//TFSecurityType
                securityType = tfsecurityType;
            }
            if(item[GB_AC_FIELD["Name"]]==""){//TFName
                item[GB_AC_FIELD["Name"]] = item[GB_AC_FIELD["TFName"]];
            }
            /*
            if(item[GB_AC_FIELD["MICCode"]]==""&&ExchToMICMap.hasOwnProperty(item[GB_AC_FIELD["TFExchangeID"]])){
                item[GB_AC_FIELD["MICCode"]]=ExchToMICMap[item[GB_AC_FIELD["TFExchangeID"]]];
            }
            */
            pid=item[GB_AC_FIELD["PerformanceId"]];
            if(pid==""){
                if(item[GB_AC_FIELD["TFExchangeID"]]&&tfsecurityType&&item[GB_AC_FIELD["TFTicker"]]){
                    item[GB_AC_FIELD["PerformanceId"]] =item[GB_AC_FIELD["TFExchangeID"]]+":"+tfsecurityType+":"+item[GB_AC_FIELD["TFTicker"]];
                    pid = item[GB_AC_FIELD["PerformanceId"]];
                }
            }
            if(ticker==""){
                continue;
            }
            if(tempPidMap.hasOwnProperty(pid)){
                continue;
            }
            _setCategory(item);
            arrkey =GB_SECURITY_NAME[item[GB_AC_FIELD["SecurityType"]]];
            if (!iData[arrkey]) {
                iData[arrkey] = [];
            }
            idMap[pid]=item;
            tempPidMap[pid]=true;
            iData[arrkey].push(item);
        }
        cacheData[cacheCallback[requestID].key] = iData;
        if (Util.isFunction(cacheCallback[requestID].callback)) {
            cacheCallback[requestID].callback(iData);
            cacheCallback[requestID] = null;
            delete cacheCallback[requestID];
        }
    };
    return {
        getData: function(cacheurl,key, fixCondition,prefixCondition, callback){
            if (!cacheData.hasOwnProperty(cacheurl)) {
                var requestID = new Date().getTime() + "";
                cacheCallback[requestID] = {
                    callback: callback,
                    key: cacheurl
                };
                var data = $.extend(true,{},prefixCondition,{kw:encodeURIComponent(key),id:requestID,acbinstid:config.instid});
                if(fixCondition){
                    data["fixCondition"]=fixCondition;
                }
                $.getJSON(config.path+dataUrls + "?callback=?",data,function(data){_dataOnArrived(data);}); 
            } else {
                callback(cacheData[cacheurl]);
            }
        },
        getCache:function(key){
            return cacheData[key];
        },
        setAutoCompletePath:function(p){
            config.path=p;
        },
        init:function(acbPath,acbInstid){
            if(!isInit){
                isInit=true;
                config.path = acbPath||Util.isFunction(QSAPI.getQSPath)?QSAPI.getQSPath():"./";
                config.instid = acbInstid||Util.isFunction(QSAPI.getInstID)?QSAPI.getInstID():"QSDEMO";
            }
        }
    };
})();

QSAPI.Widget.AutoComplete = function(container,config,callbacks,id){
    //init
    QSAPI.Widget.AutoCompleteDataManager.init();
    var subscriptions = {};
    var container=container||$(document.body);
    var scrollPanel= null;
    var cfg={
        showSearch:false,
        mouseOverable:true,
        showInput:false
    };
    $.extend(true,cfg,config);
    var callback={
        onOpenSearch:function(){
            if (typeof workspaceManager!='undefined'&&Util.isFunction(workspaceManager.openSearchDlg)) {
                workspaceManager.openSearchDlg();
                _hide();
            }
        }   
    };
    $.extend(true,callback,callbacks);
    subscribeID = id;
    var GMICMap={};
    var GExchMap={};
    if(QSAPI.DataManager){
        GMICMap = QSAPI.DataManager._getMICExangeMap();
        GExchMap =  QSAPI.DataManager._getExchangeMap();
    }
    var acbDom = {dom: null,wrap: null,tip:null,scroll:null};
    var mouseoverObj = null;
    var _hide=function(){
        acbDom.dom.hide();
        for(var input in subscriptions){
            subscriptions[input].trigger("heightChange",{width:0,height:0});
        }
    },_init=function(){
        if (acbDom.dom == null) {
            acbDom.dom = $("<div class='qs-autoCompleteBox'><div><div class='qs-autoCompleteBox-scroll'><div class='qs-autoCompleteBox-wrap'><table></table></div></div></div>"+(cfg.showSearch?"<div class='advance-search-link'><a href='javascript:void(0)'>Advanced Search</a></div>":""));
            acbDom.wrap = acbDom.dom.find(".qs-autoCompleteBox-wrap");
            acbDom.scroll = acbDom.dom.find(".qs-autoCompleteBox-scroll");
            acbDom.search = acbDom.dom.find(".advance-search-link");
            acbDom.table = acbDom.wrap.find("table");
            _hide();
        }
        container.append(acbDom.dom);
        _bindEvent();
        
    },_bindEvent=function(){
        _mouseOver();
        _mouseClick();
        _documentMouseDown();
        if(cfg.showSearch){
            acbDom.search.bind("click.autocompletebox-self", function(){
                if(Util.isFunction(callback.onOpenSearch)){
                    callback.onOpenSearch();
                }
            });
        }
    },_bindGo=function(){
        if(cfg.showInput){
            var self=this;
            with({inputid:subscribeID}){
                container.find(".qs-autoCompleteBox-input .go-"+subscribeID).bind("click.autocompletebox-self",
                    function(){
                        _trigger(inputid,true);
                    }
                );
            }
        }
    },_mouseOver = function(){
        acbDom.wrap.bind("mouseover.autocompletebox-self", function(e){
            clearTimeout(mouseoverObj);
            mouseoverObj = setTimeout(function(){
                if(!cfg.mouseOverable){
                    return;
                }
                var o = $(e.target).closest("tr");
                acbDom.wrap.find("tr").removeClass("mover");
                if (o.length > 0&&o.prop("class").indexOf("qs-autocomplete-column-title")==-1) {
                    o.addClass("mover");
                    var id = acbDom.dom.attr("inputid");
                    subscriptions[id].mouseOver(parseInt(o.attr("columnindex")));
                }
            }, 0);
        });
    },_mouseClick = function(){
        acbDom.wrap.bind("click.autocompletebox-self", function(e){
            _triggerClick();
        });
    },_triggerClick = function(){
        var id = acbDom.dom.attr("inputid");
        subscriptions[id]._setInputData();
    },_trigger = function(inputId,subMit){
        if (subscriptions[inputId]) {
            subscriptions[inputId].select(subMit);
        }
    },_documentMouseDown = function(){//auto hide
        $(document).bind("mousedown.autocompletebox-self",function(e){
            if(!$.contains(acbDom.dom[0],e.target)){
                _hide();
            }
        });
    };
    _init();
    var returnMethod={
        setMouseOver:function(mouseOverable){
            cfg.mouseOverable = mouseOverable;
        },
        /**
         * it will be called when component registration
         * @param {Object} id  input id
         * @param {Object} callback
         */
        subscribe: function(inputId, config, itemCB){
            if(Util.isValid(inputId,true,true)){
                var itemConfig=$.extend(true,cfg ,config);
                var itemCallback=$.extend(true,callback,itemCB);
                subscriptions[inputId] = new QSAPI.Widget.AutoCompleteBoxItem(inputId, itemConfig, itemCallback, this);
            }
        },
        /**
         * unSubscription the conponent
         * @param {Object} id
         */
        unSubscribe: function(inputId){
            if (subscriptions[inputId]) {
                subscriptions[inputId].clear();
                delete subscriptions[inputId];
            }
        },
        getPidByTicker: function(inputId,ticker){
            if (subscriptions[inputId]) {
               return subscriptions[id].getPidByTicker(ticker);
            }
        },
        _getMICMap:function(c){
            return GMICMap[c];
        },
        _getExchMap:function(c){
            return GExchMap[c];
        },
        trigger: function(inputId){
            _trigger(inputId);
        },
        setTicker:function(inputId,v){
            if(subscriptions[inputId]){
                subscriptions[inputId].setTicker(v);
            }
        },
        getDoms:function(){
            return acbDom;
        }
    };
    if(cfg.showInput){
        container.append('<div class="qs-autoCompleteBox-input"><input id="'+subscribeID+'" class="qs-ui-ipt" type="text" value=""><a class="qs-ui-btn go-'+subscribeID+'" href="javascript:void(0)">GO</a></div>');
        subscriptions[subscribeID] = new QSAPI.Widget.AutoCompleteBoxItem(subscribeID, cfg, callback, returnMethod);
        _bindGo();
    }
    return returnMethod;
};

QSAPI.Widget.AutoCompleteBoxItem = function(inputId, cfg, callback, acbObj){
    this.id = inputId;
    this.acbObj = acbObj;
    this.instid = Util.isFunction(QSAPI.getInstID)? QSAPI.getInstID():'';
    this.callback = {};
    $.extend(true,this.callback,callback);
    this.selectedIndex = 0;
    this.lastHeight=0;
    this.isMobile = /WebKit.+Mobile/i.test(navigator.userAgent);
    this.cfg = $.extend(true, {
        fixHeight:true,// if fixHeight==true, it depends on the height of body. if fixHeight == true, it doesn't display the scrollbar.
        showCUSP:false,
        needRemember:true,
        focusClear:true,
        showSearch:false,
        searchCount:{},
        allowExchange:{},//{"USA":{}}
        defaultCountry:"USA",
        //fixCondition:"",
        //ING :"ST,FE,FC,XI,FO,FOREX,1,2,10"
        prefixCondition: {"condition":"1,2,8"},//ST,FE,FC,XI,FO,FOREX "ST,FE,FC,XI,FO,FOREX,2"
        preciseQuery: true,
        category:["Equities","Mutual Fund","Option"]//["Equities", "Funds", "Forex", "Bonds", "ETF", "Closed-End Fund", "Mutual Fund", "Index","Option"]
    }, cfg);
    if(cfg.category){
        this.cfg.category = cfg.category;
    }
    this.input = null;
    this.config = {
        moverDelay: 10,
        textChangeDelay: 300,
        hlColor: "#93A7C3",
        hlBlod: true,
        filter:new QSAPI.Widget.AutoCompleteFilter(Util.isFunction(QSAPI.getInstID)?QSAPI.getInstID():"QSDEMO")
    };
    this.dataMap={};
    this.textChangeTimeout = null;
    this.mouseOutTimeout = null;
    this.boxIsAvailable = false;
    this.data={};
    this.securityToField={
        "Equities":["ST",1],
        "Funds":["Funds"],
        "Futures":["Futures",3],
        "Index":["XI",10],
        "Forex":["FOREX"],
        "ETF":["FE"],
        "CEF":["FC"],
        "MutualFund":["FO",8],
        "Bonds":["Bonds",7,9,16],
        "Option":[2],
        "Others":[13]
    };
    this.securityToCount={
        //"ST":5
    };
    this.searchData = {
        "Equities": { data: [], ml: 12, dl: 0, al: 0 },
        "Funds": {data: [], ml: 5, dl: 0, al: 0}, 
        "Forex": { data: [], ml: 5,  dl: 0, al: 0 },
        "Bonds": {data: [],ml: 5, dl: 0,al: 0}, 
        "Index": { data: [],ml: 5,dl: 0,al: 0 },
        "ETF": {data: [],  ml: 5, dl: 0, al: 0 },
        "Closed-End Fund": {data: [],ml: 5, dl: 0,al: 0 }, 
        "Mutual Fund": { data: [],  ml: 5, dl: 0,al: 0}, 
        "Option": { data: [],  ml: 5, dl: 0,al: 0}
    };  //key:,data-len:,max-len:,actual-len:
    //this.config = $.extend(true, this.config, option);
    this.direction = "down";
    this.storeValue=null;
    this.totalColumnCount = 0;
    this.url = null;
    this.scrollPanel = null;
    this.intervalScroll = [];
    this.scrollMouseOverTime = null;
    this.init();
};

QSAPI.Widget.AutoCompleteBoxItem.prototype = {
    _getSecurityCountString:function(securitys){
        var sec = securitys.split(",");
        for(var i=0,l=sec.length;i<l;i++){
            if(Util.isValid(this.securityToCount[sec[i]],true,true)){
                sec[i]=String.format("{0}-{1}",sec[i],this.securityToCount[sec[i]]);
            }
        }
        return sec.join(",");
    },
    _inputKeyUpDelay:function(e){
        if (!this.boxIsAvailable) {
            this.acbObj.getDoms().dom.css({
                top: this.input.offset().top + this.input.outerHeight() + "px",
                left: this.input.offset().left
            });
        }
        var sVal = this.config.filter.setValue(this.input.val());
        if (typeof QS_Validator!='undefined'&& Util.isValid(sVal,true,true,true)&&!QS_Validator.test(sVal, 'ticker')) {
            this.input.val(QS_Validator.sliceInvalidChar(sVal,'ticker'));
            return;
        }
        if (sVal == "") {
            this.hide();
            return;
        }
        if (e.keyCode == 13) {
            this.select();
            return;
        }
        var requestURL = this._getRequestURL(this.cfg.prefixCondition);
        this._setTickerCache(sVal,this.input.val(),true);
        this.url = requestURL + "&kw=" + sVal.toUpperCase();
        var self =this;
        QSAPI.Widget.AutoCompleteDataManager.getData(this.url,sVal + (this.cfg.preciseQuery ? "" : "*"), $.extend(true,{},this.cfg.fixCondition),$.extend(true,{},this.cfg.prefixCondition), function(data){
            self._createUI(data);
        });
        this.textChangeTimeout = null;
    },
    _inputKeyUp:function(e){
        var self = this;
        if (e.keyCode == 40 || e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 13) {
            return;
        }
        this.boxIsAvailable = false;
        if (this.textChangeTimeout != null) {
            clearTimeout(this.textChangeTimeout);
        }
        this.textChangeTimeout = setTimeout(function(){
            self._inputKeyUpDelay(e);
        }, this.config.textChangeDelay);
    },
    _inputKeyDown:function(e){
        var sVal = this.config.filter.setValue(this.input.val());
        if (e.keyCode == 13 && sVal != "") {
            this.select();
            return;
        }
        if (e.keyCode == 40) {//down
            this._WASD(true);
        } else if (e.keyCode == 38) {//up
            this._WASD(false);
        } else if (e.keyCode == 37) {//left
            this._WASD(false);
        } else if (e.keyCode == 39) {//right
            this._WASD(true);
        }
    },
    init: function(){
        var self = this;
        var dom = $("#" + self.id);
        this.input = dom;
        dom.bind("keyup.autocompletebox-input", function(e){self._inputKeyUp(e);});
        dom.bind("keydown.autocompletebox-input", function(e){self._inputKeyDown(e);});
        dom.bind("click.autocompletebox-input", function(e){
            if(self.cfg.focusClear){
                dom.val("");
            }
        });
        dom.bind("blur.autocompletebox-input", function(e){
            if(self.cfg.needRemember){
                var last=self.data.lastClientValue||self.data.lastValue;
                self.input.val(last);
            }
            self.input.attr("editValue","");
        });
        this.trigger("load",self.id);
        this._setResultCount(this.cfg.searchCountConfig);
        if(this.cfg.prefixCondition["condition"]){
            this.cfg.prefixCondition["condition"] = this._getSecurityCountString(this.cfg.prefixCondition["condition"]);
        }
    },
    _setResultCount:function(cfg){
        if(Util.isValid(cfg,true,true)){
            var secFields=[],securityCategoryName=null;
            for(var k in cfg){//
                secFields = this.securityToField[k];
                if(Util.isValid(secFields,true,true)){
                    for(var i=0,l=secFields.length;i<l;i++){
                        securityCategoryName = GB_SECURITY_NAME[secFields[i]];
                        this.securityToCount[secFields[i]]=cfg[k];
                        if(securityCategoryName){
                            this.searchData[securityCategoryName] = {
                                data: [], 
                                ml: cfg[k],
                                dl: 100,
                                al: 100
                            }
                        }
                    }
                }
            }
        }
        for(var sec in GB_SECURITY_NAME){
            if(!this.searchData[GB_SECURITY_NAME[sec]]){
                this.searchData[GB_SECURITY_NAME[sec]] = {
                    data: [],
                    ml: 100,
                    dl: 100,
                    al: 100
                }
            }
        }
    },
    changeBoxPosition: function(){
        if (this.input != null) {
            this._adjustPos();
        }
    },
    getPidByTicker:function(ticker){
        var rowTicker=this._getDefaultTicker(ticker);
        if(rowTicker){
            return {pid:d[GB_AC_FIELD["PerformanceId"]],ticker:d[GB_AC_FIELD["Ticker"]],exch:d[GB_AC_FIELD["MICCode"]]};
        }
        return null;
    },
    _getDefaultTicker:function(ticker){
        var data = QSAPI.Widget.AutoCompleteDataManager.getCache(this.url),temp = null,d = null;
        if(!Util.isValid(data,true,true)){
            return null;
        }
        for (var i = 0; i < this.cfg.category.length; i++) {
            temp = data[this.cfg.category[i]];
            if (temp) {
                for (var j = 0; j < temp.length; j++) {
                    if(!temp[j][GB_AC_FIELD["Ticker"]]){
                        continue;
                    }
                    if (temp[j][GB_AC_FIELD["Ticker"]] == ticker.toUpperCase()) {
                        d = temp[j];
                        if (d[GB_AC_FIELD["CountryName"]]&&d[GB_AC_FIELD["CountryName"]] == this.cfg.defaultCountry) {//priority
                            return d;
                        }
                    }
                }
            }
        }
        return null;
    },
    setTicker:function(v){//{ticker:,exch:,pid:}
        if (!Util.isValid(v,true,true)||!v.ticker) {
            return;
        }
        this._setTickerCache(v.ticker,v.clientTicker);      
        this.input.val(v.clientTicker||v.ticker);
    },
    select: function(submit){
        if(this.data.realValue!=""){
            var d=this._getDefaultTicker(this.data.realValue);
            if (d != null) {
                this._execCallBack($.extend(true,{},d),submit);
            } else {
                if(this.data.realValue){
                    this._execCallBack({
                        ticker: this.data.realValue,
                        exch:""
                    },submit);
                }
            }
        }
    },
    mouseOver:function(y){
        this.selectedIndex = y;
    },
    _getRequestURL: function(cfg){
        var url = "";
        for (var o in cfg) {
            if (o != null) {
                url += "&" + o + "=" + cfg[o];
            }
        }
        return url;
    },
    _canViewInUI:function(row){
        if($.isEmptyObject(this.cfg.allowExchange)) return true;//don't config
        var _country=row[GB_AC_FIELD["CountryName"]],_exchange=row[GB_AC_FIELD["TFExchangeID"]];
        if(!this.cfg.allowExchange[_country]) return false;
        if(!this.cfg.allowExchange[_country][_exchangeId]) return false;
        return true;
    },
    _pretreatmentData: function(data){
        this.boxIsAvailable = false;
        if (!Util.isValid(this.input,true,true)||!Util.isValid(data,true,true,true)) {
            return;
        }
        var ival = this.config.filter.setValue(this.input.val());
        if (ival == "") {
            return;
        }
        if (ival.indexOf("$") != -1) {//special future
            ival = "\\$" + ival.substr(1, ival.length);
        }
        var rgx = new RegExp(ival, "i");
        //var rgxPrecise = new RegExp("^"+ival+"$", "i");
        var cat = this.cfg.category, tc = null, td = null, tmatch = null, flag = false;
        tex = null, sd = null, arr1 = [], arr2 = [];
        for (var i = 0; i < cat.length; i++) {
            tc = cat[i], td = data[tc];
            sd = this.searchData[tc];
            sd.data.length = 0, sd.dl = 0, sd.al = 0, arr1 = [], arr2 = [];
            if (Util.isValid(td,true,true,true)) {
                for (var j = 0; j < td.length; j++) {
                    flag = false;//allowExchange
                    if(!this._canViewInUI(td[j])){
                        continue;
                    }
                    tex = $.extend(true, {}, td[j]);
                    tex.origin = tex[GB_AC_FIELD["Ticker"]];
                    tex.ticker = tex.origin;
                    if (tex.origin == "") {
                        continue;
                    }
                    if(tex[GB_AC_FIELD["SecId"]]){
                        this.dataMap[tex[GB_AC_FIELD["SecId"]]] = td[j];
                    }
                    if(!tex[GB_AC_FIELD["SecId"]]||tex[GB_AC_FIELD["SecId"]]==""){
                        this.dataMap[td[j][GB_AC_FIELD["PerformanceId"]]]=td[j];
                    }
                    //ticker should be same
                    tmatch = td[j][GB_AC_FIELD["Ticker"]].match(rgx);
                    if (tmatch != null) {
                        flag = true;
                        tex.ticker = tex[GB_AC_FIELD["Ticker"]].replace(rgx, "<b class='highlight'>" + tmatch[0] + "</b>");
                        arr1.push(tex);
                    } else {
                        tmatch = tex[GB_AC_FIELD["Name"]].match(rgx);
                        if (tmatch != null) {
                            flag = true;
                            tex[GB_AC_FIELD["Name"]] = td[j][GB_AC_FIELD["Name"]].replace(rgx, "<b class='highlight'>" + tmatch[0] + "</b>");
                            arr2.push(tex);
                        }else if(this.cfg.showCUSP){
                            flag = true;
                            if(tex[GB_AC_FIELD["CUSIP"]]&&ival.toUpperCase()==tex[GB_AC_FIELD["CUSIP"]].toUpperCase()){
                                tex.ticker = "<b class='highlight'>" + tex[GB_AC_FIELD["Ticker"]] + "</b>";
                            }

                            arr2.push(tex);
                        }
                    }
                    if (flag) {
                        this.boxIsAvailable = true;
                        this.config.filter.genClientData(this.input.val(),tex);
                    }
                }
                sd.data = arr1.concat(arr2);
                sd.dl = sd.data.length;
                sd.al = Math.min(sd.dl,sd.ml);
            }
        }
    },
    _createUI: function(data){
        this.selectedIndex = 0;
        this.direction = "down";
        this._pretreatmentData(data);
        if (!this.boxIsAvailable) {
            this.hide();
            return;
        }
        this.acbObj.getDoms().table.html(this._buildContentUI(this.cfg.category));
        this.acbObj.getDoms().dom.show();
        this.trigger("heightChange",{width:this.acbObj.getDoms().table.width(),height:this.acbObj.getDoms().table.height()});
        this.acbObj.getDoms().dom.attr("inputid",this.id);
        this._adjustPos();
    },
    _buildContentUI: function(category){
        var strArr = [], tc = null, rowCount = 0, td = null,_tempSecid = "",ticker=null,exchName="";
        for (var i = 0; i < category.length; i++) {
            tc = category[i];
            td = this.searchData[tc];
            if (td.al == 0) {
                continue;
            }
            var flag=false;
            for (var j = 0; j < this.searchData[tc].al; j++) {
                exchName = this._filterFields(td.data[j][GB_AC_FIELD["MICCode"]], td.data[j][GB_AC_FIELD["TFExchangeID"]]);
                //if(exchName=="") continue; //morningstar fund don't have exchange name
                if(!flag){
                    flag=true;
                    strArr.push("<tr columnIndex='-"+strArr.length+"' class='qs-autocomplete-column-title'><td colspan='"+(this.config.filter.getColumnsCount()+2)+"' >"+tc+"</td></tr>");
                }
                _tempSecid=this._getSecId(td.data[j]);
                ticker = td.data[j].origin;
                strArr.push("<tr columnIndex='" + strArr.length + "' realValue='"
                        + ticker + "' secid='" + _tempSecid
                        + "' pid='" + td.data[j][GB_AC_FIELD["PerformanceId"]] + "' miccode='"
                        + td.data[j][GB_AC_FIELD["MICCode"]]
                        + "' clientTicker='"+(td.data[j]["orginClientTicker"]||ticker)+"'>"
                        +"<td class='qs-autocomplete-col-ticker'>"+ td.data[j].ticker+ "</td>"
                        + this.config.filter.createRowUI(tc,td.data[j])
                        + "<td class='acb-right'>" + exchName + "</td></tr>");
            }
        }
        this.totalColumnCount = strArr.length;
        return strArr.join("");
    },
    _getSecId:function(ticker){
        var secId=ticker[GB_AC_FIELD["SecId"]];
        if(!secId||secId==""){
            secId=ticker[GB_AC_FIELD["PerformanceId"]];
        }
        return secId||ticker["ticker"];
    },
    _filterFields:function(s,exchId){
        if(!Util.isValid(s,true,true)){
            return;
        }
        var exchMap=null;
        if(Util.isValid(exchId,true,true,true)){
            exchMap = this.acbObj._getExchMap(exchId);
            
        }
        if(exchMap&&$.trim(exchMap)!=""){
            s=exchMap;
        }else{
            s=this.acbObj._getMICMap(s)||s;
        }
        return s.replace(/\$/ig,"");
    },
    _adjustPos: function(){
        var acbox = this.acbObj,boxdoms=acbox.getDoms(),inputOffset = this.input.offset(), acboxOffset = boxdoms.dom.offset(), inputOutHeight = this.input.outerHeight(true);
        var _top = inputOffset.top-$(document.body).scrollTop();
        var _acb_height =0;
        
        var winHeight = $(window).height(),winWidth = $(window).width();
        if (winHeight == null) {
            winHeight = 0;
        }
        var adSearchHeight = 0;
        if(this.cfg.showSearch){
            adSearchHeight = boxdoms.search.outerHeight(true);
        }
        var acbDomTotalHeight = 0;
        if (this.input != null) {
            if((winHeight-_top)<80&&this.cfg.fixHeight){
                _acb_height=_top - adSearchHeight;
                var upTop = _top-(this.acbObj.getDoms().table.height()+adSearchHeight);
                if(upTop<0){  // up
                    upTop = 0;
                }
                boxdoms.dom.css({
                    top: upTop + "px",
                    left: inputOffset.left
                });
                acbDomTotalHeight = this.acbObj.getDoms().table.height()+adSearchHeight;
            }else{
                boxdoms.dom.css({
                    top: _top + inputOutHeight + "px",
                    left: inputOffset.left
                });
                acbDomTotalHeight = this.acbObj.getDoms().table.height() + _top + inputOutHeight;
                _acb_height =winHeight - (_top + inputOutHeight+adSearchHeight+2);
            }
        }
        
        var acbDomWidth = 0;
        if (acbDomTotalHeight > winHeight&&this.cfg.fixHeight) {  // if fixHeight == true display the scrollbar.
            if (!this.acbObj.scrollPanel) {
                this.acbObj.scrollPanel = new Util.ScrollPanel(this.acbObj.getDoms().scroll);
            }
            acbDomWidth=this.acbObj.getDoms().table.width() + 12+2;
            if(acbDomWidth>winWidth&&this.isMobile){
                acbDomWidth=winWidth;
            }
            this.acbObj.scrollPanel.reSize(acbDomWidth,_acb_height );
        } else {
            if (this.acbObj.scrollPanel) {
                acbDomWidth=this.acbObj.getDoms().table.width();
                if(acbDomWidth>winWidth&&this.isMobile){
                    acbDomWidth=winWidth;
                }
                var self = this;
                if($.browser.msie){
                //boxdoms.wrap.css({"width":this.acbObj.getDoms().table.width()});
                this.acbObj.scrollPanel.reSize(acbDomWidth, this.acbObj.getDoms().table.height()+2);
                /*
                    boxdoms.wrap.css({"width":this.acbObj.getDoms().table.width()});
                    setTimeout(function(){
                        acbDomWidth=self.acbObj.acbDom.table.width();
                        if(acbDomWidth>winWidth&&self.isMobile){
                            acbDomWidth=winWidth;
                        }
                        self.acbObj.scrollPanel.reSize(acbDomWidth, self.acbObj.acbDom.table.height()+2);
                    },300)
                    */
                }else{
                    this.acbObj.scrollPanel.reSize(acbDomWidth, this.acbObj.getDoms().table.height());
                    
                }
                //this.acbObj.scrollPanel.reSize(acbDomWidth, this.acbObj.getDoms().table.height());
            }else{
                acbDomWidth=this.acbObj.getDoms().table.width();
            }
        }
        //alert(this.isMobile);
        //alert(/WebKit.+Mobile/i.test(navigator.userAgent));
        //if(acbDomWidth>0){//&&!this.isMobile
            if(winWidth<(acbDomWidth+acboxOffset.left)){
                boxdoms.dom.css({
                left: winWidth-acbDomWidth-2
            });
            }
        //}
        
    },
    _getAvailableIndex:function(i,isDown){
        if (i < 0||this.acbObj.getDoms().wrap.find("tr[columnindex='" + (-i) + "']").length> 0) {
            return this._getAvailableIndex(Math.abs(i) + (isDown?1:-1), isDown);
        } else {
            if (this.acbObj.getDoms().wrap.find("tr[columnindex='" + i + "']").length > 0) {
                return i;
            } else {
                return isDown?1:this.acbObj.getDoms().wrap.find("tr").length-1;
            }
        }
    },
    _WASD:function(isDown){
        var obj = this.acbObj.getDoms().wrap;
        this.selectedIndex = this._getAvailableIndex(Math.abs(this.selectedIndex) + (isDown?1:-1),isDown);
        if(this.acbObj.scrollPanel){
            var per = this.selectedIndex / (this.totalColumnCount - 1);
            this.acbObj.setMouseOver(false);
            if(this.scrollMouseOverTime){
                clearTimeout(this.scrollMouseOverTime);
            }
            this.acbObj.scrollPanel.scrollbarY.scrollPercentTo(per);
            var self = this;
            this.scrollMouseOverTime =setTimeout(function(){
                self.acbObj.setMouseOver(true);
            },500);
        }
        obj.find("tr").removeClass("mover");
        var liObj=obj.find("tr[columnindex='" + this.selectedIndex + "']");
        liObj.addClass("mover");
    },
    _setInputData: function(){
        var obj = this.acbObj.getDoms().wrap.find("tr[columnindex='" + this.selectedIndex + "']");
                var v1 = obj.attr("miccode"), clientTicker = obj.attr("clientTicker"), v2 = obj
                .attr("realValue"), v3 = obj.attr("pid"), secid = obj
                .attr("secid");
        
        if (Util.isValid(v2,true,true)) {
            if (v1 == "FLIT") {//forex
                if (v3 == "") {
                    v3 = "245:" + v2 + v1;
                }
            }
            var allData = {ticker: v2,exch: v1, clientTicker:clientTicker};
            if(secid&&this.dataMap[secid]!="undefined"&&this.dataMap[secid]!=null){
                allData = $.extend(true,allData,this.dataMap[secid]);
            }
            this._execCallBack(allData);
        }
        this.hide();
    },
    _execCallBack: function(v,submit){
        this.input.val(v.clientTicker||v.ticker);
        this.data.realClientValue=v.clientTicker||v.ticker;
        if(QSAPI.TickerFactory){
            var self=this;
            QSAPI.TickerFactory.create([this._getSecId(v)],{
                onSuccess:function(tickerlist){
                    if(Util.isFunction(self.callback.onClick)){
                        self.callback.onClick(tickerlist[0]);
                    }
                    if(submit&&Util.isFunction(self.callback.onSubmit)){
                        self.callback.onSubmit(tickerlist[0]);
                    }
                }
            });
        }else{
            if(Util.isFunction(this.callback.onClick)){
                this.callback.onClick(v);
            }
            if(submit&&Util.isFunction(this.callback.onSubmit)){
                this.callback.onSubmit(val,v);
            }
        }
        this._setTickerCache("","");
        this.hide();
        this.selectedIndex=0;
    },
    _setTickerCache:function(ticker,clientTicker,isOnlyR){
        if(isOnlyR){
            this.data.realValue = $.trim(ticker).toUpperCase();
            this.data.realClientValue = String($.trim(clientTicker||ticker)).toUpperCase();
        }else{
            this.data.lastValue = this.data.realValue;
            this.data.lastClientValue = this.data.realClientValue;
            this.data.realValue = $.trim(ticker).toUpperCase();
            this.data.realClientValue = String($.trim(clientTicker||ticker)).toUpperCase();
        }
    },
    trigger:function(event,data){
        switch(event){
            case "heightChange":
                if(Util.isFunction(this.callback.onHeightChange)){
                    if(this.lastHeight!=data.height){
                        this.callback.onHeightChange(data);
                        this.lastHeight=data.height;
                    }
                }
                break;
            case "load":
                if(Util.isFunction(this.callback.onLoad)){
                    this.callback.onLoad(data);
                }
                break;
            default:
                break;
        }
    },
    hide: function(){
        var boxdom = this.acbObj.getDoms().dom;
        if (boxdom) {
            boxdom.hide();//hide current dom
        }
        this.selectedIndex = 0;
        this.trigger("heightChange",{width:0,height:0});
    },
    clear: function(){
        this.input.unbind("autocompletebox-input");
        for (var f in this) {
            if (!f || f == 'clear') {
                continue;
            }
            this[f] = null;
            delete this[f];
        }
    }
};
 
